package Test.限流算法;

/**
 * @Author: kirito
 * @Description:
 * 漏桶限流算法（Leaky Bucket Algorithm）是一种流量控制算法，用于控制流入网络的数据速率，以防止网络拥塞。
 * 它的思想是将数据包看作是水滴，漏桶看作是一个固定容量的水桶，数据包像水滴一样从桶的顶部流入桶中，
 * 并通过桶底的一个小孔以一定的速度流出，从而限制了数据包的流量。
 *
 * 漏桶限流算法的基本工作原理是：对于每个到来的数据包，都将其加入到漏桶中，并检查漏桶中当前的水量是否超过了漏桶的容量。
 * 如果超过了容量，就将多余的数据包丢弃。如果漏桶中还有水，就以一定的速率从桶底输出数据包，保证输出的速率不超过预设的速率，从而达到限流的目的。
 *
 * 流入的水滴，可以看作是访问系统的请求，这个流入速率是不确定的。
 * 桶的容量一般表示系统所能处理的请求数。
 * 如果桶的容量满了，就达到限流的阀值，就会丢弃水滴（拒绝请求）
 * 流出的水滴，是恒定过滤的，对应服务按照固定的速率处理请求。
 *
 * 优点
 *      可以平滑限制请求的处理速度，避免瞬间请求过多导致系统崩溃或者雪崩。
 *      可以控制请求的处理速度，使得系统可以适应不同的流量需求，避免过载或者过度闲置。
 *      可以通过调整桶的大小和漏出速率来满足不同的限流需求，可以灵活地适应不同的场景。
 *
 * 缺点
 *      需要对请求进行缓存，会增加服务器的内存消耗。
 *      对于流量波动比较大的场景，需要较为灵活的参数配置才能达到较好的效果。
 *      但是面对突发流量的时候，漏桶算法还是循规蹈矩地处理请求，这不是我们想看到的啦。
 *      流量变突发时，我们肯定希望系统尽量快点处理请求，提升用户体验嘛。
 * @Date: 2024/2/28 14:58
 * @Version: 1.0
 */

public class 漏桶 {
    /**
     * LeakyBucket 类表示一个漏桶,
     * 包含了桶的容量和漏桶出水速率等参数，
     * 以及当前桶中的水量和上次漏水时间戳等状态。
     */
    public class LeakyBucket {
        private int capacity = 100;
        private int count = 0;
        private int rate = 10; //每时间单位多少个请求
        private long lastTime = 0L;//上次漏水的时间戳

        public synchronized boolean func() {
            if (count >= capacity) {
                return false;
            }
            count++;
            return true;
        }


        // 模拟处理请求的方法
        public void processRequests() {
            new Thread(() -> {
                while (true) {
                    long currentTimeMillis = System.currentTimeMillis();
                    long elapsedTime = currentTimeMillis - lastTime; // 计算时间差
                    int processedRequests = (int) (elapsedTime * rate / 1000); // 计算应该处理的请求数量
                    if (processedRequests > 0) {
                        int toProcess = Math.min(processedRequests, count); // 实际可以处理的请求数量
                        count -= toProcess; // 更新桶中的请求计数
                        lastTime = currentTimeMillis; // 更新上次处理时间
                    }
                    try {
                        // 模拟处理请求需要一定时间
                        Thread.sleep(1000 / rate);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}
